/**
 * Copyright (c) 2015-2020, wss 王山山
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wss.conversion.meta;

import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;

import com.jfinal.core.Controller;
import com.wss.conversion.Constants;
import com.wss.conversion.annotations.Route;
import com.wss.conversion.config.ConfigUtil;
import com.wss.utils.ReflectionUtil;
import com.wss.utils.StringUtil;
import com.wss.utils.annotations.NotNull;

/**
 * 表示控制器的相关信息：
 * 			1.控制器 url
 * 			2.视图路径前缀
 * 			3.是否被扫描注册
 * 
 * @author wss
 *
 */
public final class ControllerMeta {
	/*
	 * 视图文件的文件夹
	 */
	private final String BASE_PATH = ConfigUtil.getApplicationConfig().getWeb().getViewFolder();
	
	/*
	 * 控制器对应的Class
	 */
	private Class<?> controllerClass;
	/*
	 * 控制器的注解
	 */
	private Route route;
	/*
	 * 控制器是否有注解
	 */
	private boolean hasRoute;
	
	public ControllerMeta(@NotNull Class<?> controllerClass) {
		Objects.requireNonNull(controllerClass);
		
		this.controllerClass = controllerClass;
		Optional<Route> routeOptional = ReflectionUtil.getAnnotationByType(controllerClass, Constants.ControllerConstants.ROUTE_CLASS);
		this.hasRoute = routeOptional.isPresent();
		this.route = hasRoute ? routeOptional.get() : null;
	}
	
	public String getView() {
		if (hasValue(e -> StringUtil.isNotBlank(route.view()))) {
			return route.view();
		}
		return Constants.ControllerConstants.URI_SEPARATOR + BASE_PATH + Constants.ControllerConstants.URI_SEPARATOR + getControllerName();
	}
	
	public String getUrl() {
		if (hasValue(e -> StringUtil.isNotBlank(route.value()))) {
			return route.value();
		}
		return Constants.ControllerConstants.URI_SEPARATOR + getControllerName();
	}
	
	private boolean hasValue(Predicate<Route> consumer) {
		return hasRoute && consumer.test(route);
	}
	
	private String getControllerName() {
		String controllerName = StringUtil.subtractSuffix(controllerClass.getSimpleName(), Constants.ControllerConstants.CONTROLLER_SUFFIX);
		return StringUtil.firstLetterLowerCase(controllerName);
	}
	
	public boolean isScan() {
		return hasRoute ? route.isScan() : true;
	}

	@SuppressWarnings("unchecked")
	public Class<? extends Controller> getControllerClass() {
		return (Class<? extends Controller>) controllerClass;
	}

	@Override
	public String toString() {
		return "Route: " + this.getUrl() + " View: " + this.getView() + " IsScan: " + this.isScan();
	}
}
